package com.utc.cards.player.jade.agent.playerAgent;

import jade.core.AID;
import jade.core.Agent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.content.Context;
import android.content.Intent;

import com.utc.cards.Constants;
import com.utc.cards.games.GameContainer;
import com.utc.cards.model.HostModel;
import com.utc.cards.model.PlayerModel;
import com.utc.cards.model.card.Card;
import com.utc.cards.model.deck.Deck;
import com.utc.cards.model.game.GameStatus;
import com.utc.cards.model.game.InfoType;
import com.utc.cards.model.player.Hands;
import com.utc.cards.model.player.HumanPlayer;
import com.utc.cards.model.player.IAPlayer;
import com.utc.cards.model.player.IPlayer;

public class PlayerAgent extends Agent implements IPlayerAgent
{

    private static final long serialVersionUID = -7812647282008239070L;
    private static Logger log = LoggerFactory.getLogger(PlayerAgent.class);

    private PlayerModel model;
    private Context context;

    private String selectedGame = "";
    private String gmail;

    @Override
    protected void setup()
    {
        super.setup();
        Object[] args = getArguments();
        if (args != null && args.length > 0)
        {
            if (args[0] instanceof Context)
            {
                context = (Context) args[0];
            }
            else
            {
                log.error("Missing Context arg during agent setup");
            }
            if (args[1] instanceof PlayerModel)
            {
                model = (PlayerModel) args[1];
            }
            else
            {
                log.error("Missing PlayerModel arg during agent setup");
            }
            if (args[2] instanceof String)
            {
                gmail = (String) args[2];
            }
            else
            {
                log.error("Missing gmail arg during agent setup");
            }
        }

        // Add initial behaviours
        // écoute du choix du jeu
        // écoute de la liste des joueurs
        log.debug("add behaviour PlayerListenerBehaviour to PlayerAgent");
        addBehaviour(new PlayerListenerBehaviour(this));

        // tentative d'inscription automatique au jeu
        joinHostGame();

        // expose l'interface pour la rendre accessible par les activity
        registerO2AInterface(IPlayerAgent.class, this);
    }

    @Override
    public void joinHostGame()
    {
        log.debug("JoinHostGame()...");
        log.debug("add behaviour PlayerSubscriptionBehaviour to PlayerAgent");
        // envoi une demande d'inscription au lancement de l'agent, et a la
        // demande si la partie est pleine et qqn est parti
        addBehaviour(new PlayerSubscriptionBehaviour(this));
    }

    // via PlayerListenerBehaviour, GameAgent sent InfoType.PLAY_TURN
    @Override
    public void onPlayerTurn()
    {
        // ICI on utilise Iplayer pour faire jouer le coup,
        // si humain bin ca ne fait rien (= attente du Drag&Drop)
        // si IA : jouer une carte au hasard parmis celles conseillées, si
        // aucune conseillée jouer carte au hasard parmi celles en main
        log.debug("onPlayerTurn()");
        log.debug("model:" + model);
        log.debug("model.player:" + model.getPlayer());
        log.debug("onPlayerTurn()");

        model.getPlayer().playTurn(this);

        if (model.getPlayer() instanceof HumanPlayer)
        {

            Intent intent = new Intent();
            intent.setAction(Constants.PLAYER_TURN);
            log.debug("Sending INTENT " + intent.getAction());
            context.sendBroadcast(intent);
        }
    }

    @Override
    public void onPlayerTurnStop()
    {
        log.debug("onPlayerTurnStop()");
        if (model.getPlayer() instanceof HumanPlayer)
        {

            Intent intent = new Intent();
            intent.setAction(Constants.PLAYER_TURN_STOP);
            log.debug("Sending INTENT " + intent.getAction());
            context.sendBroadcast(intent);
        }
    }

    @Override
    public void askAdvice()
    {
        addBehaviour(new AskAdviceBehaviour(this));
    }

    // shortcut for MAIN deck
    @Override
    public void sendCards(Deck cards)
    {
        Hands hands = new Hands();
        hands.put(IPlayer.MAIN_HAND, cards);
        sendCards(hands);
    }

    @Override
    public void sendCards(Hands hands)
    {
        log.debug("add behaviour PlayerPlayCardBehaviour to PlayerAgent");
        addBehaviour(new PlayerPlayCardBehaviour(this, hands));
    }

    @Override
    public Context getContext()
    {
        return context;
    }

    @Override
    public void onGameSubscriptionAgree()
    {
        log.debug("onGameSubscriptionAgree()");
        Intent intent = new Intent(Constants.LOCK_CONNEXION);
        log.debug("Sending INTENT " + intent.getAction());
        context.sendBroadcast(intent);
        notifyInfo("Connexion réussie de " + getAID().getLocalName());

        // on envoie un retour à l'hote pour lui dire qu'il pourra démarrer (quand tout le monde sera pret)
        // SPECIFIC à l'IA, pour les humains on attend l'activity
        if (getAID().getLocalName().contains("Joueur IA"))
        {
            log.debug("onCreate() : informing host IA is ready to play");
            sendPlayerActive();
        }
    }

    @Override
    public void onGameSubscriptionRefuse()
    {
        log.debug("onGameSubscriptionRefuse()");
        notifyInfo("Connexion refusée");
    }

    /**
     * pour afficher une popup
     * 
     * @param info
     */
    @Override
    public void notifyInfo(String info)
    {
        log.debug("notifyInfo()");
        Intent intent = new Intent(Constants.POP_INFO);
        intent.putExtra(InfoType.INFO.name(), info);
        log.debug("Sending INTENT " + intent.getAction());
        context.sendBroadcast(intent);
    }

    /**
     * met a jour la liste affichée des participants
     * 
     * @param players
     */
    @Override
    public void notifyPlayersChanged(String[] players)
    {
        log.debug("notifyPlayersChanged FDP: ");
        for (String s : players)
        {
            log.debug("notifyPlayersChanged FDP:" + s);
        }

        log.debug("notifyPlayersChanged()");
        Intent intent = new Intent(Constants.PLAYER_LIST);
        intent.putExtra(Constants.PLAYER_LIST, players);
        log.debug("Sending INTENT " + intent.getAction());
        context.sendBroadcast(intent);
    }

    // via PlayerListenerBehaviour, GameAgent sent InfoType.GAME_START
    @Override
    public void onGameStart()
    {

        log.debug("gamename : {}", selectedGame);
        log.debug("game : {}", GameContainer.getGameByName(selectedGame));
        log.debug("model : {}", model);
        log.debug("model.game : {}", model.getGame());

        // gros trucage pour passer le jeu courant sur les ia sans message...
        if (model.getPlayer() instanceof IAPlayer)
        {
            model.setGame(GameContainer.getGameByName(HostModel.Instance().getGame().getName()));
        }
        else
        {
            model.setGame(GameContainer.getGameByName(selectedGame));
        }

        // les IA ne doivent pas changer cet état, cela arrive trop tot et l'objet model est partagé entre IA et hote
        if (!getLocalName().contains("Joueur IA"))
        {
            // change gameStatus
            model.getGame().setStatus(GameStatus.IN_GAME);
        }

        // on informe la vue : l'activity
        Intent intent = new Intent();
        intent.setAction(Constants.SHOW_GAME);
        log.debug("Sending INTENT " + intent.getAction());
        context.sendBroadcast(intent);
    }

    @Override
    public void onGameEnd()
    {
        // On ne fait rien, l'affichage du vainqueur se fait sur la tablette
    }

    @Override
    public void onGameSelection(String gameName)
    {
        log.debug("onGameSelection({})", gameName);
        selectedGame = gameName;
        // update UI, affiche le nom du jeu
        Intent intent = new Intent(Constants.GAME_NAME);
        log.debug("Sending INTENT " + intent.getAction());
        intent.putExtra(Constants.GAME_NAME, selectedGame);
        context.sendBroadcast(intent);
    }

    @Override
    public String getGmail()
    {
        return gmail;
    }

    @Override
    public PlayerModel getModel()
    {
        return model;
    }

    @Override
    public void onScoreReception()
    {
        // Abandon de la méthode
    }

    @Override
    public void onCardsChanged(Hands hands, InfoType infoType)
    {
        log.debug("onCardsChanged: " + infoType);

        Intent intent = new Intent();

        intent.setAction(Constants.CARDS_CHANGED);

        intent.putExtra(Constants.UPDATE_VIEW_TYPE, infoType);

        String cardsSerialized = null;

        if (hands != null)
        {
            cardsSerialized = new String();

            for (Card card : hands.getHands().get(IPlayer.MAIN_HAND))
            {
                cardsSerialized += card.getResourceId() + "|";
            }

            cardsSerialized = cardsSerialized.substring(0, cardsSerialized.length() - 1);
        }

        intent.putExtra(Constants.CARDS_IDS, cardsSerialized);

        log.debug("Sending INTENT " + intent.getAction());
        context.sendBroadcast(intent);
    }

    @Override
    public void onAdvice(Card card)
    {
        log.debug("onAdvice(Card card)");

        if (model.getPlayer() instanceof HumanPlayer)
        {
            Intent intent = new Intent();
            intent.setAction(Constants.ADVICE);
            intent.putExtra(Constants.CARD_ID, card.getResourceId());
            log.debug("Sending INTENT " + intent.getAction());
            context.sendBroadcast(intent);
        }
        else if (model.getPlayer() instanceof IAPlayer)
        {
            Hands hands = new Hands();
            Deck deck = new Deck();
            deck.add(card);
            hands.put(IPlayer.MAIN_HAND, deck);
            log.debug("add behaviour PlayerPlayCardBehaviour to GameAgent");
            addBehaviour(new PlayerPlayCardBehaviour(this, hands));
        }
    }

    @Override
    public String getAgentName()
    {
        return getLocalName();
    }

    @Override
    public AID getAgentAID()
    {
        return getAID();
    }

    public void setSelectedGameName(String gamename)
    {
        selectedGame = gamename;
    }

    @Override
    public void notifyPlayerIsReady()
    {
        addBehaviour(new PlayerReadyBehaviour(this));

    }

    @Override
    public void sendPlayerActive()
    {
        log.debug("add behaviour SendPlayerActiveBehaviour to PlayerAgent");
        addBehaviour(new SendPlayerActiveBehaviour(this));
    }
}
